﻿using System;
using System.Collections.Generic;
using BattleCity.Classes;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;

namespace BattleCity.GameObjects
{
    public class Enemy : Tank
    {
        //Переменная, задающая первоначальное направление движения
        int WhereToMove = 1;
        //Количество ходов в свободном пространстве перед поворотом значение
        int FreeMoveCount = 150;

        Me _target;
        Base _baseObj;

        Animation _empty;
        #region Дополнительные анимации для танков типа 4
        Animation _moveUpAnimationG;
        Animation _moveDownAnimationG;
        Animation _moveLeftAnimationG;
        Animation _moveRightAnimationG;
        Animation _idleUpG;
        Animation _idleDownG;
        Animation _idleLeftG;
        Animation _idleRightG;

        Animation _moveUpAnimationY;
        Animation _moveDownAnimationY;
        Animation _moveLeftAnimationY;
        Animation _moveRightAnimationY;
        Animation _idleUpY;
        Animation _idleDownY;
        Animation _idleLeftY;
        Animation _idleRightY;
        #endregion

        Vector2 _direct;
        Random _rnd = new Random();
        //Переменная для исключения повторного поворота объекта при движении вдоль стены или границы экрана
        bool _flag = true;
        //Переменная для исключения повторного поворота объекта при движении в свободном пространстве
        bool _flag1 = false;
        public int _iter;
        byte _type;
        bool _isBonusly, _desFlag, _isFreezed;

        public double _lifeTime;
        public short ScoresGive { get; private set; }

        public Enemy(BattleCityGame game, ref AnimationPlayer spr, Vector2 sprPosition,
            Dictionary<string, Animation>[] _animList, byte eType, SoundEffect killSound, Me player, Base baza)
            : base(game, ref spr, sprPosition)
        {
            _type = eType;
            _dieSound = killSound;
            LoadAnimation(_animList[_type - 1]);
            _sprite.PlayAnimation(_empty);
            SetEnemyProperties();
            IsAlive = true;
            _target = player;
            _baseObj = baza;
            _isMultiShoot = false;
        }
        protected override void LoadAnimation(Dictionary<string, Animation> animList)
        {
            _empty = animList["empty"];
            if (_type == 4)
            {
                _moveUpAnimationG = animList["moveUpG"];
                _moveDownAnimationG = animList["moveDownG"];
                _moveLeftAnimationG = animList["moveLeftG"];
                _moveRightAnimationG = animList["moveRightG"];
                _idleUpG = animList["idleUpG"];
                _idleDownG = animList["idleDownG"];
                _idleLeftG = animList["idleLeftG"];
                _idleRightG = animList["idleRightG"];
                _moveUpAnimationY = animList["moveUpY"];
                _moveDownAnimationY = animList["moveDownY"];
                _moveLeftAnimationY = animList["moveLeftY"];
                _moveRightAnimationY = animList["moveRightY"];
                _idleUpY = animList["idleUpY"];
                _idleDownY = animList["idleDownY"];
                _idleLeftY = animList["idleLeftY"];
                _idleRightY = animList["idleRightY"];
            }
            base.LoadAnimation(animList);
        }
        void SetEnemyProperties()
        {
            switch (_type)
            {
                case 1:
                    ScoresGive = 100;
                    _speed = 4;
                    ShootSpeed = 8f;
                    Lives = 1;
                    break;
                case 2:
                    ScoresGive = 200;
                    _speed = 6;
                    ShootSpeed = 8f;
                    Lives = 1;
                    break;
                case 3:
                    ScoresGive = 300;
                    _speed = 4;
                    ShootSpeed = 16f;
                    Lives = 1;
                    break;
                case 4:
                    ScoresGive = 400;
                    _speed = 4;
                    ShootSpeed = 8f;
                    Lives = 4;
                    break;
                case 5:
                    ScoresGive = 100;
                    _speed = 4;
                    ShootSpeed = 8f;
                    Lives = 1;
                    _isBonusly = true;
                    break;
                case 6:
                    ScoresGive = 200;
                    _speed = 6;
                    ShootSpeed = 8f;
                    Lives = 1;
                    _isBonusly = true;
                    break;
                case 7:
                    ScoresGive = 300;
                    _speed = 4;
                    ShootSpeed = 16f;
                    Lives = 1;
                    _isBonusly = true;
                    break;
                case 8:
                    ScoresGive = 400;
                    _speed = 4;
                    ShootSpeed = 8f;
                    Lives = 4;
                    _isBonusly = true;
                    break;
            }
        }
        void MoveAnimation(int direction)
        {
            switch (direction)
            {
                case 1:
                    if (_type == 4)
                    {
                        switch (Lives)
                        {
                            case 1:
                                _sprite.PlayAnimation(_moveLeftAnimation);
                                break;
                            case 2:
                                _sprite.PlayAnimation(_moveLeftAnimationG);
                                break;
                            case 3:
                                _sprite.PlayAnimation(_moveLeftAnimationY);
                                break;
                            case 4:
                                goto case 2;
                        }
                    }
                    else
                        _sprite.PlayAnimation(_moveLeftAnimation);
                    break;
                case 2:
                    if (_type == 4)
                    {
                        switch (Lives)
                        {
                            case 1:
                                _sprite.PlayAnimation(_moveRightAnimation);
                                break;
                            case 2:
                                _sprite.PlayAnimation(_moveRightAnimationG);
                                break;
                            case 3:
                                _sprite.PlayAnimation(_moveRightAnimationY);
                                break;
                            case 4:
                                goto case 2;
                        }
                    }
                    else
                        _sprite.PlayAnimation(_moveRightAnimation);
                    break;
                case 3:
                    if (_type == 4)
                    {
                        switch (Lives)
                        {
                            case 1:
                                _sprite.PlayAnimation(_moveUpAnimation);
                                break;
                            case 2:
                                _sprite.PlayAnimation(_moveUpAnimationG);
                                break;
                            case 3:
                                _sprite.PlayAnimation(_moveUpAnimationY);
                                break;
                            case 4:
                                goto case 2;
                        }
                    }
                    else
                        _sprite.PlayAnimation(_moveUpAnimation);
                    break;
                case 4:
                    if (_type == 4)
                    {
                        switch (Lives)
                        {
                            case 1:
                                _sprite.PlayAnimation(_moveDownAnimation);
                                break;
                            case 2:
                                _sprite.PlayAnimation(_moveDownAnimationG);
                                break;
                            case 3:
                                _sprite.PlayAnimation(_moveDownAnimationY);
                                break;
                            case 4:
                                goto case 2;
                        }
                    }
                    else
                        _sprite.PlayAnimation(_moveDownAnimation);
                    break;
            }
        }
        public override void Initialize()
        {
            _sprite.PlayAnimation(_portal);
            base.Initialize();
        }
        //Функция для реализации "взгляда" объекта. Если он видит объект преследования - возвращает True, иначе - False
        bool SimulateMove(Vector2 testPosition)
        {
            //Находится ли объект игрока так, что объект управляемый компьютером может "видеть" его.
            //Предположим, что да
            bool isCollide = false;
            bool collisionDetected = false;
            Vector2 newVector;
            Vector2 oldPosition = this.SprPosition;
            if (testPosition.X == -1 & testPosition.Y == -1)
            {
                Me spr = _target;
                while (collisionDetected == false)
                {
                    newVector = (this.SprPosition - spr.SprPosition);
                    if (newVector.X > 0)
                        MoveLeft(_speed);
                    else if (newVector.X < 0)
                        MoveRight(_speed);
                    if (newVector.Y > 0)
                        MoveUp(_speed);
                    else if (newVector.Y < 0)
                        MoveDown(_speed);
                    if (IsCollideWithWall(this))
                    {
                        collisionDetected = true;
                        isCollide = false;
                    }
                    if (IsCollideWithObject(spr))
                    {
                        collisionDetected = true;
                        isCollide = true;
                    }
                }
            }
            else //Проверяем на столкновение объекта и стены
            //эта часть функции реализует "зрение" объекта
            {
                while (collisionDetected == false)
                {
                    newVector = (this.SprPosition - testPosition);
                    if (newVector.X > 0)
                        MoveLeft(Math.Abs(newVector.X / 90));
                    else if (newVector.X < 0)
                        MoveRight(Math.Abs(newVector.X / 90));
                    if (newVector.Y > 0)
                        MoveUp(Math.Abs(newVector.Y / 90));
                    else if (newVector.Y < 0)
                        MoveDown(Math.Abs(newVector.Y / 90));
                    if (IsCollideWithWall(this))
                    {
                        collisionDetected = true;
                        isCollide = true;
                    }
                    if (CheckBounds())
                    {
                        collisionDetected = true;
                        isCollide = true;
                    }
                    if (Math.Abs(newVector.X) < 0.1 & Math.Abs(newVector.Y) < 0.1)
                    {
                        collisionDetected = true;
                        isCollide = false;
                    }
                }
            }
            this.SprPosition = oldPosition;
            return isCollide;
        }
        bool CheckAttackDistanceLength(Vector2 direction)
        {
            return ((Math.Abs(direction.X) <= 160 && Math.Abs(direction.Y) <= 23) || 
                (Math.Abs(direction.Y) <= 160 && Math.Abs(direction.X) <= 23));
        }
        void SeekAndDestroy()
        {
            Me spr = _target;
            //найдем разницу между координатами преследователя и игрока
            _direct = (this.SprPosition - spr.SprPosition);
            //Если разность по X положительная переместим преследователя влево
            //с учетом того, что стены для него непроницаемы.
            if (_direct.X > 0)
            {
                _dir = Direction.Left;
                MoveLeft(_speed);
                _sprite.PlayAnimation(_moveLeftAnimation);
                if ((CheckAttackDistanceLength(_direct) || ScanLandForBase()) && !_isShootNow)
                    Shoot();
                while (IsCollideWithWall(this))
                    MoveRight((_speed / 40));
            }
            //При отрицательной разности по X
            //переместим объект вправо
            if (_direct.X < 0)
            {
                _dir = Direction.Right;
                MoveRight(_speed);
                _sprite.PlayAnimation(_moveRightAnimation);
                if ((CheckAttackDistanceLength(_direct) || ScanLandForBase()) && !_isShootNow)
                    Shoot();
                while (IsCollideWithWall(this))
                    MoveLeft((_speed / 40));
            }
            //При положительной разности по Y
            //переместим объект вверх
            if (_direct.Y > 0)
            {
                _dir = Direction.Up;
                MoveUp(_speed);
                _sprite.PlayAnimation(_moveUpAnimation);
                if ((CheckAttackDistanceLength(_direct) || ScanLandForBase()) && !_isShootNow)
                    Shoot();
                while (IsCollideWithWall(this))
                    MoveDown((_speed / 40));
            }
            //При отрицательной разности по Y переместим
            //объект вниз
            if (_direct.Y < 0)
            {
                _dir = Direction.Down;
                MoveDown(_speed);
                _sprite.PlayAnimation(_moveDownAnimation);
                if ((CheckAttackDistanceLength(_direct) || ScanLandForBase()) && !_isShootNow)
                    Shoot();
                while (IsCollideWithWall(this))
                    MoveUp((_speed / 40));
            }
        }
        bool ScanLandForBase()
        {
            Vector2 direction = this.SprPosition - _baseObj.SprPosition;
            Random rnd = new Random();
            return (((Math.Abs(direction.X) <= 48 && Math.Abs(direction.Y) <= 16) ||
                (Math.Abs(direction.Y) <= 48 && Math.Abs(direction.X) <= 16)) &&
                rnd.Next(0, 100) >= 50);
        }
        /*
         * Движение вдоль стены или в свободном пространстве
         * Направление движения
         * 1 - влево
         * 2 - вправо
         * 3 - вверх
         * 4 - вниз
         */
        void WallWalk(int direct)
        {
            if (direct == 1)
            {
                _dir = Direction.Left;
                MoveLeft(_speed);
                MoveAnimation(direct);
            }
            else if (direct == 2)
            {
                _dir = Direction.Right;
                MoveRight(_speed);
                MoveAnimation(direct);
            }
            else if (direct == 3)
            {
                _dir = Direction.Up;
                MoveUp(_speed);
                MoveAnimation(direct);
            }
            else if (direct == 4)
            {
                _dir = Direction.Down;
                MoveDown(_speed);
                MoveAnimation(direct);
            }
        }
        void Die(GameTime time)
        {
            --Lives;
            if (Lives == 0)
            {
                _target.Score += ScoresGive;
                if (_isBonusly)
                    (Game as BattleCityGame).newGame.AddBonuses();
                _dieTime = time.TotalGameTime.TotalSeconds;
                _sprite.PlayAnimation(_destroy);
                _dieSound.Play();
                (Game as BattleCityGame).newGame.numberOfEnemies--;
                (Game as BattleCityGame).newGame.destroyedEnemies++;
                (Game as BattleCityGame).newGame.DestroyedEnemiesList.Add(_type);
                Game.Components.Remove((Game as BattleCityGame).newGame.tankList[20 - (Game as BattleCityGame).newGame.destroyedEnemies]);
            }
            else
                IsAlive = true;
        }
        public void Freeze()
        {
            _isFreezed = true;
        }
        public void UnFreeze()
        {
            _isFreezed = false;
        }
        public override void Update(GameTime gameTime)
        {
            _lifeTime += gameTime.ElapsedGameTime.TotalSeconds;
            _iter++;
            //Проигрываем анимацию портала всякое движение до конца анимации невозможно
            if (_iter <= 300)
            {
                if (_iter <= 150)
                    _sprite.PlayAnimation(_empty);
                else
                    _sprite.PlayAnimation(_portal);
            }
            else if (IsAlive)
            {
                //Если на пути нет препятствий Перемещение к объекту игрока
                if (!_isFreezed)
                {
                    if (SimulateMove(new Vector2(-1, -1)) && _target.IsAlive)
                        SeekAndDestroy();
                    else
                    {
                        //Перемещение вдоль стены или в свободном пространстве
                        WallWalk(WhereToMove);
                        //Разрешить повороты вдоль стены
                        _flag = true;
                        if (IsCollideWithWall(this) || CheckBounds())
                        {
                            //Разрешить повороты в пространстве
                            //Найдя "разрыв" в стене объект повернет в него
                            _flag1 = true;
                            if (WhereToMove == 1 && _flag)
                            {
                                WhereToMove = 3;
                                //Если сделан поворот
                                //Нельзя сразу же делать поворот в другую сторону
                                _flag = false;
                            }
                            if (WhereToMove == 2 && _flag)
                            {
                                WhereToMove = 4;
                                _flag = false;
                            }
                            if (WhereToMove == 3 && _flag)
                            {
                                WhereToMove = 2;
                                _flag = false;
                            }
                            if (WhereToMove == 4 && _flag)
                            {
                                WhereToMove = 1;
                                _flag = false;
                            }
                        }
                        //Блок обработки перемещений в пространстве и в "разрывах" стен

                        //Если выполнено количество шагов, заданное в переменной FreeMoveCount
                        //Установить новое случайное значение для этой переменной
                        //Разрешить повороты в свободном пространстве
                        if (FreeMoveCount < 0)
                        {
                            FreeMoveCount = _rnd.Next(20, 100);
                            _flag1 = true;
                        }
                        //Если не было поворота вдоль стены и разрешены повороты в пространстве
                        //И выше объекта нет препятствия, то - сменить направление движения на "вверх"
                        if (_flag && _flag1 && WhereToMove == 2 && !SimulateMove(new Vector2(this.SprPosition.X, this.SprPosition.Y - 8)))
                        {
                            WhereToMove = 3;
                            _flag1 = false;
                            _flag = false;
                        }
                        //Если при движении вверх обнаруживаем, что нет препятствия слева
                        //поворачиваем влево
                        if (_flag && _flag1 && WhereToMove == 3 && !SimulateMove(new Vector2(this.SprPosition.X - 8, this.SprPosition.Y)))
                        {
                            WhereToMove = 1;
                            _flag1 = false;
                            _flag = false;
                        }
                        //Если при движении влево обнаруживаем, что нет препятсвия внизу
                        //двигаемся вниз
                        if (_flag && _flag1 && WhereToMove == 1 && !SimulateMove(new Vector2(this.SprPosition.X, this.SprPosition.Y + 8)))
                        {
                            WhereToMove = 4;
                            _flag1 = false;
                            _flag = false;
                        }
                        //Если двигались вниз и обнаружили, что справа нет препятствия
                        //Двигаемся вправо
                        if (_flag && _flag1 && WhereToMove == 4 && !SimulateMove(new Vector2(this.SprPosition.X + 8, this.SprPosition.Y)))
                        {
                            WhereToMove = 2;
                            _flag1 = false;
                            _flag = false;
                        }
                    }
                }
                Check();
                //Уменьшаем на 1 количество допустимых ходов в свободном пространстве
                FreeMoveCount--;
            }
            if (!IsAlive && !_desFlag)
            {
                Die(gameTime);
                _desFlag = true;
            }
            if (!IsAlive && gameTime.TotalGameTime.TotalSeconds - _dieTime >= 1)
                this.Dispose();
            base.Update(gameTime);
        }
    }
}